﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Collections;
using System.Threading.Tasks;
using System.Media;

namespace HanoiTower
{
    public partial class HanoiTowerForm : Form
    {
        int totalTier = 3;          // 汉诺塔的最大层数 
        int interval = 1024;        // 默认动画速度
        ArrayList[] alTower = new ArrayList[3];
        char[] chs = new char[] { 'A', 'B', 'C' };
        Font font;                  // 柱子的显示字体
        int fontsize = 16;          // 字体大小
        int tireHeight = 10;        // 每层的高度
        int towerWidth = 140;       // 塔的宽度 
        int MAXTIRES = 10;          // 最多支持10块
        private bool PlaySounds = true;

        System.Threading.Thread t;// 用于显示动画的线程。
        Brush[] brushes = {
            new SolidBrush(Color.FromArgb(255, 255, 0, 0)),
            new SolidBrush(Color.FromArgb(255, 255, 165, 0)),
            new SolidBrush(Color.FromArgb(255, 255, 255, 0)),
            new SolidBrush(Color.FromArgb(255,0, 255, 0  )),
            new SolidBrush(Color.FromArgb(255, 0, 127, 255)),
            new SolidBrush(Color.FromArgb(255, 0, 0, 255 )),
            new SolidBrush(Color.FromArgb(255, 139, 0, 255)),
            Brushes.White,
            Brushes.LightGray,
            Brushes.DarkGray,
        };

        /// <summary>
        /// 移动汉诺塔的主要过程，将n-1块从start移动到end，使用temp作为缓冲。
        /// </summary>
        /// <param name="num_of_tires">总层数</param>
        /// <param name="start">开始位置</param>
        /// <param name="temp">缓冲位置</param>
        /// <param name="end">结束位置</param>
        //控制台方案
        private void hanno(int num_of_tires, char start, char temp, char end)
        {
            if (num_of_tires > 0)
            {
                hanno(num_of_tires - 1, start, end, temp);
                Console.WriteLine("Move " + start + " To " + end);
                hanno(num_of_tires - 1, temp, start, end);
            }
        }

        //GUI界面
        private void hanno(int num_of_tires, int start, int end, int temp)
        {
            if (num_of_tires > 0)
            {
                hanno(num_of_tires - 1, start, temp, end);
                MoveTower(start, end);
                hanno(num_of_tires - 1, temp, end, start);
            }
        }


        public HanoiTowerForm()
        {
            InitializeComponent();

        }


        private void Form1_Load(object sender, EventArgs e)
        {
            Text = "汉诺塔演示程度1.0 (2008/10/15)";
            Text = "汉诺塔演示程度1.1 (2023/03/08)";
            Text = "汉诺塔演示程度1.2 (2024/03/09)";
            //三根柱子
            alTower[0] = new ArrayList();
            alTower[1] = new ArrayList();
            alTower[2] = new ArrayList();

            tbTireCount.Maximum = MAXTIRES;
            tbTireCount.Minimum = 1;
            tbTireCount.Value = 3;
            totalTier = tbTireCount.Value;
            alTower[0].Clear();
            alTower[1].Clear();
            alTower[2].Clear();

            for (int i = 0; i < totalTier; i++)
                alTower[0].Add(i);

            font = new Font("宋体", fontsize, FontStyle.Bold); // 显示字体
            pbView.Invalidate();
        }
        //储存时间间隔
        int[] intervals = { 0, 800, 800, 800, 512, 256, 64, 32, 16, 8, 4, 2 };
        private void button1_Click(object sender, EventArgs e)
        {
            btnStart.Enabled = false;
            tbTireCount.Enabled = false;
            totalTier = tbTireCount.Value;
            interval = intervals[totalTier];
            alTower[0].Clear();
            alTower[1].Clear();
            alTower[2].Clear();
            lbHistory.Items.Clear();
            for (int i = 0; i < totalTier; i++)
                alTower[0].Add(i);

            pbView.Invalidate();
            Application.DoEvents();
            System.Threading.Thread.Sleep(interval);
            t = new System.Threading.Thread(new System.Threading.ThreadStart(Test));
            t.IsBackground = true;
            t.Start();
        }


        int layer = 0;
        private void Test1()
        {
            layer++;
            Console.WriteLine(layer);
            Test1();
        }

        private void Test()
        { 
            hanno(totalTier, 0, 2, 1); 
            btnStart.Enabled = true;
            tbTireCount.Enabled = true;//滑动条控件 tbTireCount，允许用户再次更改圆盘数量
            MessageBox.Show("从A塔到C塔的移动完成！", "完成", MessageBoxButtons.OK, MessageBoxIcon.Information);
        }



        private void MoveTower(int a, int b)
        {
            
            lbHistory.Items.Add($"Step {lbHistory.Items.Count + 1,-4} Move {chs[a]} To {chs[b]}");
            lbHistory.SelectedIndex = lbHistory.Items.Count - 1;
            label4.Text = lbHistory.Items.Count.ToString();
            PlaySound();
            alTower[b].Insert(0, alTower[a][0]);//将第a个塔索引为0的圆盘移动到塔b上
           
            alTower[a].RemoveAt(0);//移除a
           
            pbView.Invalidate();// 调用Invalidate方法使pictureBox1控件区域无效，触发控件的Paint事件，以便重新绘制界面以反映最新的圆盘移动状态
            Application.DoEvents();// 使应用程序立即处理所有挂起的Windows消息，确保界面能够立即响应更新操作。
            System.Threading.Thread.Sleep(interval);
        }


        private void pictureBox1_Paint(object sender, PaintEventArgs e)
        {
            var g = e.Graphics;//绘制图像
            char[] chs = { 'A', 'B', 'C' };
            float poleWidth = 3;

            float intervalWidth = pbView.Width * 0.05f;
            float intervalHeight = pbView.Height * 0.1f;
            float boxWidth = (pbView.Width - intervalWidth * 4) / 3.0f;
            float boxHeight = pbView.Height - intervalHeight * 2;

            int tireCount = totalTier;
            float[] tireWidths = new float[tireCount];
            for (int i = 0; i < tireWidths.Length; i++)
            {
                tireWidths[i] = boxWidth * 0.08f * (i + 1);
            }
            Font idFont = new Font("宋体", boxHeight * 0.04f, FontStyle.Bold);
            for (int tower_id = 0; tower_id < alTower.Length; tower_id++)
            {
                float bX = intervalWidth + (intervalWidth + boxWidth) * tower_id;
                float bY = intervalHeight;

                g.FillRectangle(Brushes.LightGray, bX, bY, boxWidth, boxHeight);
                g.DrawRectangle(Pens.DarkGray, bX, bY, boxWidth, boxHeight);


                float hbarWidth = boxWidth * 0.9f;
                float hbarHeight = poleWidth;
                float hbarX = bX + (boxWidth - hbarWidth) / 2;
                float hbarY = bY + boxHeight - intervalHeight;
                g.FillRectangle(Brushes.Black, hbarX, hbarY, hbarWidth, hbarHeight);


                float vbarX = bX + boxWidth / 2;
                float vbarY = bY + intervalHeight;
                float vbarWidth = poleWidth;
                float vbarHeight = boxHeight - intervalHeight * 2;
                g.FillRectangle(Brushes.Black, vbarX, vbarY, vbarWidth, vbarHeight);

                g.DrawString($"{chs[tower_id]}", font, Brushes.Black, vbarX - fontsize / 2, vbarY + vbarHeight + 4);


                float tireHeight = (boxHeight * 0.8f) / MAXTIRES - 2;
                float y0 = hbarY - (alTower[tower_id].Count - 1) * tireHeight;// - poleWidth;

                for (int level = 0; level < alTower[tower_id].Count; level++)
                {

                    int tireID = (int)alTower[tower_id][level];
                    float tireWidth = tireWidths[tireID]; // boxWidth * (1 - 0.1f * level - 0.1f);  // 0.9, 0.8, ..., 0.1
                    float xi = bX + (boxWidth - tireWidth) / 2 + poleWidth / 2;
                    float yi = y0 + tireHeight * (level - 1);

                    g.FillRectangle(brushes[tireID], xi, yi, tireWidth, tireHeight);
                    g.DrawRectangle(Pens.Black, xi, yi, tireWidth, tireHeight);
                    g.DrawString($"{tireID + 1}", idFont, Brushes.Black, vbarX - idFont.Size / 2 + 1, yi + idFont.Size * 0.5f);
                }
            }
        }


        private void label4_Click(object sender, EventArgs e)
        {

        }

        private void HanoiTowerForm_SizeChanged(object sender, EventArgs e)
        {
            pbView.Invalidate();
        }

        private void tbTireCount_Scroll(object sender, EventArgs e)
        {
            lbHistory.Items.Clear();
            totalTier = tbTireCount.Value;
            alTower[0].Clear();
            alTower[1].Clear();
            alTower[2].Clear();
            label4.Text = "0";
            for (int i = 0; i < totalTier; i++)
                alTower[0].Add(i);
            pbView.Invalidate();
        }

        private void ckGrayed_CheckedChanged(object sender, EventArgs e)
        {
            if (ckGrayed.Checked)
            {
                int colorInterval = 16;
                int colorOffset = 80;
                brushes = new Brush[10];
                for (int i = 0; i < brushes.Length; i++)
                {
                    brushes[i] = new SolidBrush(Color.FromArgb(255, 
                        i * colorInterval + colorOffset, 
                        i * colorInterval + colorOffset, 
                        i * colorInterval + colorOffset));
                }
            }
            else
            {
                brushes = new Brush[10]{
                    new SolidBrush(Color.FromArgb(255, 255, 0, 0)),
                    new SolidBrush(Color.FromArgb(255, 255, 165, 0)),
                    new SolidBrush(Color.FromArgb(255, 255, 255, 0)),
                    new SolidBrush(Color.FromArgb(255, 0, 255, 0)),
                    new SolidBrush(Color.FromArgb(255, 0, 127, 255)),
                    new SolidBrush(Color.FromArgb(255, 0, 0, 255)),
                    new SolidBrush(Color.FromArgb(255, 139, 0, 255)),
                    Brushes.White,
                    Brushes.LightGray,
                    Brushes.DarkGray,
                };

            }
            pbView.Invalidate();
        }
        //声音
        private void ckSound_ClickChanged(object sender, EventArgs e)
        {
           PlaySounds = ckSound.Checked;
        }

        

        private void PlaySound()
        {
            if (PlaySounds)
            {
                SoundPlayer sp = new SoundPlayer();
               
                sp.PlaySync(); // 在新线程中同步播放声音
            }
        }
    }

}
